﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Xceed.Silverlight.Data;

namespace Xceed.Silverlight.DataGrid
{
  public partial class DataGridControl
  {

    private void RegisterColumn( Column column )
    {
      column.PropertyChanged += new PropertyChangedEventHandler( this.OnColumnPropertyChanged);
    }

    private void UnregisterColumn( Column column )
    {
      column.PropertyChanged -= new PropertyChangedEventHandler( this.OnColumnPropertyChanged );
    }

    private void OnColumnPropertyChanged( object sender, PropertyChangedEventArgs e )
    {
      if( e.IsPropertyChanged( ( Column col ) => col.CellContentTemplate )
        || e.IsPropertyChanged( ( Column col ) => col.CellEditorTemplate ) )
      {
        this.RefreshColumns( true );
        this.RefreshData( true );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.CellStyle )
        || e.IsPropertyChanged( ( Column col ) => col.ColumnManagerCellStyle )
        || e.IsPropertyChanged( ( Column col ) => col.FilterCellStyle )
        || e.IsPropertyChanged( ( Column col ) => col.InsertionCellStyle )
        || e.IsPropertyChanged( ( Column col ) => col.CellContentStyle )
        || e.IsPropertyChanged( ( Column col ) => col.CellEditorStyle )
        || e.IsPropertyChanged( ( Column col ) => col.DisplayMemberBindingInfo )
        || e.IsPropertyChanged( ( Column col ) => col.CellVerticalContentAlignment )
        || e.IsPropertyChanged( ( Column col ) => col.CellHorizontalContentAlignment )
        || e.IsPropertyChanged( ( Column col ) => col.TextTrimming )
        || e.IsPropertyChanged( ( Column col ) => col.Visible ) )
      {
        this.RefreshColumns( true );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.Width )
        || e.IsPropertyChanged( ( Column col ) => col.MinWidth )
        || e.IsPropertyChanged( ( Column col ) => col.MaxWidth ) )
      {
        this.OnColumnWidthChanged( sender, e );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.TitleTemplate ) )
      {
        this.OnColumnTitleTemplateChanged( sender, e );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.DisplayTitle ) )
      {
        this.OnColumnDisplayTitleChanged( sender, e );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.CellEditorDisplayConditions ) )
      {
        this.OnColumnCellEditorDisplayConditionsChanged( sender, e );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.EditTriggers ) )
      {
        this.OnColumnEditTriggersChanged( sender, e );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.AllowResize ) )
      {
        this.OnColumnResizeChanged( sender, e );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.SortDirection ) )
      {
        this.OnColumnSortDirectionChanged( sender, e );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.AllowGroup ) )
      {
        this.OnColumnAllowGroupChanged( sender, e );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.AllowFilter ) )
      {
        this.OnColumnAllowFilterChanged( sender, e );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.ReadOnly ) )
      {
        this.OnColumnReadOnlyChanged( sender, e );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.SortFieldName ) )
      {
        this.OnColumnSortFieldNameChanged( sender, ( ValuesPropertyChangedEventArgs )e );
      }

      if( e.IsPropertyChanged( ( Column col ) => col.VisiblePosition ) )
      {
        this.OnColumnVisiblePositionChanged( sender, ( ValuesPropertyChangedEventArgs )e );
      }
    }

    private void OnColumnTitleTemplateChanged( object sender, EventArgs e )
    {
      this.RefreshColumns( true );
      this.UpdateGroupByItemsTitle();
    }

    private void OnColumnDisplayTitleChanged( object sender, EventArgs e )
    {
      // Update each GroupByItem
      this.UpdateGroupByItemsTitle();

      // Update each columnManagerCell of this column
      this.RefreshColumns( true );
    }

    private void OnColumnCellEditorDisplayConditionsChanged( object sender, EventArgs e )
    {
      var column = ( Column )sender;
      var inspector = CellEditorVisibilityInspector.Create( this ).Check( column );

      this.UpdateCellsEditorVisibility( inspector );
    }

    private void OnColumnEditTriggersChanged( object sender, EventArgs e )
    {
      this.CheckEditTriggers();
    }

    private void OnColumnResizeChanged( object sender, EventArgs e )
    {
      Column column = ( Column )sender;
      // Update Hit test Visibility for ColumnManager cells of the column
      ColumnContainer columnContainer = this.GetColumnContainer( column );
      if( columnContainer != null )
      {
        foreach( ColumnManagerCell cell in columnContainer.ColumnManagerCells )
        {
          this.UpdateColumnResizingThumbHitTestVisibility( cell );
        }
      }
    }

    private void OnColumnSortDirectionChanged( object sender, EventArgs e )
    {
      Column column = ( Column )sender;

      if( this.DataGridPanel != null )
      {
        ColumnContainer columnContainer = this.DataGridPanel.RenderedColumns.FirstOrDefault( ( cc ) => object.Equals( cc.Column, column ) );
        if( columnContainer != null )
        {
          foreach( ColumnManagerCell cell in columnContainer.ColumnManagerCells )
          {
            cell.SetSortingState( column.SortDirection, true );
          }
        }
      }

      this.SetDataSourceSorting( column.SortFieldName, column.SortDirection, true, true );
    }

    private void OnColumnSortFieldNameChanged( object sender, ValuesPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;

      if( column.SortDirection != SortDirection.None )
      {
        string oldValue = ( string )e.OldValue;
        string newValue = ( string )e.NewValue;

        this.SetDataSourceSorting( oldValue, SortDirection.None, true, false );
        this.SetDataSourceSorting( newValue, column.SortDirection, true, false );
        this.InvalidateData();
      }
    }

    private void OnColumnAllowFilterChanged( object sender, EventArgs e )
    {
    }

    private void OnColumnAllowGroupChanged( object sender, EventArgs e )
    {
      Column column = ( Column )sender;
      this.UpdateAllGroupByItemRemoveButtonVisibility();
    }

    private void OnColumnWidthChanged( object sender, EventArgs e )
    {
      Column column = ( Column )sender;
      this.UpdateColumnWidth( column );

      // No animation in this case since the width change could be from
      // the column resize drag. We want the resize to be "real time".
      UpdateRequest request = new UpdateRequest( false );
      request.UpdateDetails.ColumnSizeOrPositionOnly = true;
      this.SetColumns( request );
    }

    private void OnColumnReadOnlyChanged( object sender, EventArgs e )
    {
      Column column = ( Column )sender;

      DataGridBindingInfo current = column.DisplayMemberBindingInfo;
      if( ( current != null ) && ( current.IsAutoGenerated ) )
      {
        column.DisplayMemberBindingInfo = new DataGridBindingInfo( current.Path.Path, this.GetInheritedReadOnly( column ), current.IsAutoGenerated );
      }

      var inspector = CellEditorVisibilityInspector.Create( this ).Check( column );
      this.UpdateCellsEditorVisibility( inspector );
    }

    private void OnColumnVisiblePositionChanged( object sender, ValuesPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      List<Column> sortedColumnsList = this.GetOrderedColumns().ToList();

      int oldIndex = ( int )e.OldValue;
      int newIndex = ( int )e.NewValue;

      var count = sortedColumnsList.Count;
      var startIndex = Math.Min( oldIndex, newIndex );
      startIndex = Math.Max( 0, startIndex );

      for( var i = startIndex; i < count; i++ )
      {
        var sortedColumn = sortedColumnsList[ i ];

        if( column == sortedColumn )
          continue;

        var visiblePosition = sortedColumn.VisiblePosition;

        if( ( visiblePosition > oldIndex )
          && ( visiblePosition <= newIndex ) )
        {
          // Unregister to PropertyChanged when modifying column.VisiblePosition so that the column.VisiblePosition's callback won't do anything
          sortedColumn.PropertyChanged -= new PropertyChangedEventHandler( this.OnColumnPropertyChanged );
          sortedColumn.VisiblePosition--;
          // Register to PropertyChanged is back
          sortedColumn.PropertyChanged += new PropertyChangedEventHandler( this.OnColumnPropertyChanged );
        }
        else if( ( visiblePosition < oldIndex )
              && ( visiblePosition >= newIndex ) )
        {
          // Unregister to PropertyChanged when modifying column.VisiblePosition so that the column.VisiblePosition's callback won't do anything
          sortedColumn.PropertyChanged -= new PropertyChangedEventHandler( this.OnColumnPropertyChanged );
          sortedColumn.VisiblePosition++;
          // Register to PropertyChanged is back
          sortedColumn.PropertyChanged += new PropertyChangedEventHandler( this.OnColumnPropertyChanged );
        }
      }

      UpdateRequest request = new UpdateRequest( true );
      request.UpdateDetails.ColumnSizeOrPositionOnly = true;
      this.SetColumns( request );
    }
  }
}
